package com.dongzili.demo.common.config.redis;

import com.dongzili.demo.common.utils.ReflectUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * &#064;description:  redis set操作
 * @author dongzili
 * @param <T>
 */
@Slf4j
public class RedisSetService<T> {

    private final ZSetOperations<String, T> setOps;
    private final Class<T> tClass;
    private final String key;

    public RedisSetService(Class<T> tClass) {
        RedisTemplate<String, T> redisTemplate = RedisTemplateConfig.getRedisTemplate();
        this.setOps = redisTemplate.opsForZSet();
        this.tClass = tClass;
        this.key = "set-"+tClass.getSimpleName();
    }

    public void addOrUpdate(T value) {
        Object id = ReflectUtils.getPrimaryValue(value);
        if (id == null){
            throw new RuntimeException("主键不能为空");
        }
        if(id instanceof Number){
            setOps.add(key, value, ((Number) id).longValue());
        }else{
            setOps.add(key, value, System.currentTimeMillis());
        }
    }


    public Set<T> searchKeys(String keyword, int page, int size) {
        // 计算偏移量
        if(page == 0){page =1;}
        long start = (long) (page-1) * size;
        long end = start + size;
        // 创建扫描选项，设置匹配关键字和每次扫描的数量（即每页的大小）
        ScanOptions options;
        if(StringUtils.hasText(keyword)){
            options = ScanOptions.scanOptions().match(keyword).count(100000000).build();
        }else{
            options = ScanOptions.scanOptions().count(100000000).build();
        }

        Set<T> keys = new HashSet<>();
        try (Cursor<ZSetOperations.TypedTuple<T>> cursor = setOps.scan(key, options)) {
            // 跳过前面的元素，达到分页的效果
            for (int i = 0; i < start && cursor.hasNext(); i++) {
                cursor.next();
            }
            // 获取当前页的元素
            while (cursor.getPosition() >= start && cursor.getPosition() < end  && cursor.hasNext()) {
//                System.out.println("position: "+cursor.getPosition());
                keys.add(cursor.next().getValue());
            }
        } catch (Exception e) {
//            e.printStackTrace();
            log.error("redis set 查询失败", e);
        }
        return keys;
    }



    /**
     * 排序并分页查询
     * @param page
     * @param pageSize
     * @return
     */
    public List<T> findByPageAndSorted(int page, int pageSize) {
        int start = (page - 1) * pageSize;
        int end = start + pageSize - 1;
        Set<T> users = setOps.range(key, start, end);
        if (users != null) {
            return new ArrayList<>(users);
        }
        return Collections.emptyList();
    }
}
